
/*******************************************************************************
**                      Includes                                              **
*******************************************************************************/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "random.h"
#include "big.h"
#include "sm2.h"
#include "sm3.h"
#include "Crypto_Cfg_Defines.h"

/*******************************************************************************
**                      Static Macro Definitions                             **
*******************************************************************************/
// SM2 a
static const uint8 SM2_ECC_A[] = {
        0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC
};

// SM2 b
static const uint8 SM2_ECC_B[] = {
        0x28, 0xE9, 0xFA, 0x9E, 0x9D, 0x9F, 0x5E, 0x34,
        0x4D, 0x5A, 0x9E, 0x4B, 0xCF, 0x65, 0x09, 0xA7,
        0xF3, 0x97, 0x89, 0xF5, 0x15, 0xAB, 0x8F, 0x92,
        0xDD, 0xBC, 0xBD, 0x41, 0x4D, 0x94, 0x0E, 0x93
};

// SM2 Gx
static const uint8 SM2_ECC_GX[] = {
        0x32, 0xC4, 0xAE, 0x2C, 0x1F, 0x19, 0x81, 0x19,
        0x5F, 0x99, 0x04, 0x46, 0x6A, 0x39, 0xC9, 0x94,
        0x8F, 0xE3, 0x0B, 0xBF, 0xF2, 0x66, 0x0B, 0xE1,
        0x71, 0x5A, 0x45, 0x89, 0x33, 0x4C, 0x74, 0xC7
};

// SM2 Gy
static const uint8 SM2_ECC_GY[] = {
        0xBC, 0x37, 0x36, 0xA2, 0xF4, 0xF6, 0x77, 0x9C,
        0x59, 0xBD, 0xCE, 0xE3, 0x6B, 0x69, 0x21, 0x53,
        0xD0, 0xA9, 0x87, 0x7C, 0xC6, 0x2A, 0x47, 0x40,
        0x02, 0xDF, 0x32, 0xE5, 0x21, 0x39, 0xF0, 0xA0
};

// SM2 N-1
static sm2_bn_t SM2_BN_N_SUB_ONE = {
        0x39D54122, 0x53BBF409, 0x21C6052B, 0x7203DF6B,
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE
};

static sm2_bn_t SM2_BN_2W = {
    0x00000000, 0x00000000, 0x00000000, 0x80000000,
    0x00000000, 0x00000000, 0x00000000, 0x00000000
};

static sm2_bn_t SM2_BN_2W_SUB_ONE = {
    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF,
    0x00000000, 0x00000000, 0x00000000, 0x00000000
};

#ifndef SM2_PUT_UINT32_BE
#define SM2_PUT_UINT32_BE(n, b ,i)                       \
{                                                       \
    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
}
#endif
/*******************************************************************************
**                      Global Macro Definitions                             **
*******************************************************************************/

volatile sm2_bn_t x;                   // Temporary variable for x coordinate
volatile sm2_bn_t y;                   // Temporary variable for y coordinate
volatile sm2_bn_t r;                   // Signature component r
volatile sm2_bn_t s;                   // Signature component s
volatile sm2_bn_t e;                   // Message hash

/*******************************************************************************
** Private Function Declarations **
*******************************************************************************/

/************************************************************************************************************
 *  Cry_SM2_GenZA()
 ***********************************************************************************************************/
/*!
 * \brief         Calculates the ZA value for SM2 signature scheme.
 * \details       This function performs the following steps:
 *                1. Parameter checks (publicKey, id, hash).
 *                2. Converts the ID length from bytes to bits and stores it in big-endian format.
 *                3. Initializes the SM3 context and updates it with:
 *                   - The bit-length of the ID
 *                   - The actual ID data
 *                   - The SM2 domain parameters (A, B, Gx, Gy)
 *                   - The public key (x and y coordinates)
 *                4. Finalizes the SM3 computation, producing the ZA value in \p hash.
 *
 * \param[in]     publicKey   Pointer to the 64-byte public key buffer (x and y each 32 bytes).
 * \param[in]     id          Pointer to the ID buffer.
 * \param[in]     idlen       Length of the ID buffer in bytes.
 * \param[out]    hash        Pointer to the 32-byte buffer for the resulting ZA value.
 *
 * \return        E_OK        The ZA calculation completed successfully.
 * \return        E_NOT_OK    The ZA calculation failed (e.g., NULL pointer input).
 *
 * \pre           The calling environment must provide valid pointers and sufficient buffer sizes.
 * \context       ANY
 * \reentrant     FALSE
 * \synchronous   TRUE
 * \config        -
 **********************************************************************************************************/
static Std_ReturnType Cry_SM2_GenZA(uint8 *publicKey,const uint8 *id, uint32 idlen, uint8 *hash)
{
    uint8 idlen_char[2];
    sm3_ctx md[1];

    /* 1. Parameter checks (NULL pointers and sufficient buffer sizes) */
    if ((publicKey == NULL) || (id == NULL) || (hash == NULL)) {
        /* One or more required pointers are NULL */
        return E_NOT_OK;
    }

    /* 2. Prepare idlen_char: store (idlen << 3) in big-endian */
    if (idlen > 0x1FFFU) {
        /* Ensure idlen does not exceed 16-bit range in bits */
        return E_NOT_OK;
    }

    /* 3. Convert idlen from bytes to bits and store in big-endian format. */
    uint16 idlen_bits = (uint16)(idlen << 3);

    /* 4. Prepare idlen_char: store (idlen << 3) in big-endian */
    put_unaligned_be16(idlen_bits, idlen_char);

    /* 5. Initialize SM3 context and update */
    Cry_SM3_Init(md);

    /* 6. Update with ENTL (id length in bits) */
    Cry_SM3_Update(md, idlen_char, 2);

    /* 7. Update with actual ID data */
    Cry_SM3_Update(md, id, idlen);

    /* 8. Update with SM2 domain parameters A, B, Gx, Gy */
    Cry_SM3_Update(md, SM2_ECC_A, ECC_NUMWORD);
    Cry_SM3_Update(md, SM2_ECC_B, ECC_NUMWORD);
    Cry_SM3_Update(md, SM2_ECC_GX, ECC_NUMWORD);
    Cry_SM3_Update(md, SM2_ECC_GY, ECC_NUMWORD);

    /* 9. Update with public key: x coordinate and y coordinate */
    Cry_SM3_Update(md, publicKey, ECC_NUMWORD);
    Cry_SM3_Update(md, &publicKey[32], ECC_NUMWORD);

    /* 10. Finalize SM3 to get ZA */
    Cry_SM3_GetHash(md, hash);

    /* 11. If we reach here, everything succeeded */
    return E_OK;
}


/************************************************************************************************************
 *  Cry_SM2_SignMsg()
 ***********************************************************************************************************/
/*!
 * \brief         Signs a message using the SM2 signature scheme.
 * \details       This function implements the SM2 signature generation process, including:
 *                1. Calculation of ZA (user-specific hash based on ID and public key).
 *                2. Message hash generation using SM3.
 *                3. Computation of the signature components \( r \) and \( s \).
 *                4. Verification of the generated values to ensure validity.
 *
 * \param[in]     PrivateKey   Pointer to the 32-byte private key.
 * \param[in]     PublicKey    Pointer to the 64-byte public key (x and y each 32 bytes).
 * \param[in]     Message      Pointer to the message buffer.
 * \param[in]     MessageLen   Length of the message in bytes.
 * \param[in]     User_Id      Pointer to the user ID buffer.
 * \param[in]     User_Len     Length of the user ID in bytes.
 * \param[out]    SignatureR   Pointer to the buffer for the r component of the signature.
 * \param[out]    SignatureS   Pointer to the buffer for the s component of the signature.
 *
 * \return        Std_ReturnType  E_OK if the signature generation is successful, E_NOT_OK otherwise.
 **********************************************************************************************************/
Std_ReturnType Cry_SM2_SignMsg(uint8 *PrivateKey,uint8 *PublicKey,const uint8 *Message, uint32 MessageLen, const uint8 *User_Id, uint32 User_Len, uint8 *SignatureR, uint8 *SignatureS)
{
    Std_ReturnType Result = E_OK;          // Function result
    uint8 zhash[ECC_NUMWORD] = {0};        // ZA hash
    uint8 mhash[ECC_NUMWORD] = {0};        // Message hash
    uint8 mMessage[ECC_NUMBITS * 8] = {0}; // Combined ZA and message buffer
    uint8 TestK[32]= {0};

    sm2_point_t _P, *P = &_P;              // Temporary point structure
    sm2_bn_t d;                            // Private key in Montgomery format
    sm2_bn_t k;                            // Random number
    uint8 buf[256];                        // Random buffer
    sm2_bn_t key;                          // Private key as a big number
    sm2_bn_t dgst;                         // Hash as a big number

   
    if(USER_TESTCASE == 5U)
    {
        //Public key cryptographic algorithm SM2 based on elliptic curves- Part 5:Parameter definition, random K
        uint8 TestK[32] = {0x59,0x27,0x6E,0x27,0xD5,0x06,0x86,0x1A, 0x16,0x68,0x0F,0x3A, 0xD9,0xC0,0x2D,0xCC,0xEF,0x3C,0xC1,0xFA, 0x3C,0xDB,0xE4,0xCE, 0x6D,0x54,0xB8,0x0D, 0xEA,0xC1,0xBC,0x21};
    }

    // Step 1: Generate ZA
    if (Cry_SM2_GenZA(PublicKey,User_Id,User_Len,zhash)!= E_OK) 
    {   
        return E_NOT_OK;  // failed to generate ZA
    }

    // Step 2: Combine ZA and message
    memcpy(mMessage,zhash,ECC_NUMWORD);
    memcpy(&mMessage[ECC_NUMWORD],Message,MessageLen);

    // Step 3: Generate hash of ZA and message
    if (Cry_SM3_MainFunction(mMessage, (MessageLen + ECC_NUMWORD), mhash)!= E_OK) 
    {
        return E_NOT_OK;  // failed to generate mhash
    }
    
    // Step 4: Convert hash and private key to big numbers
    if (Cry_SM2_BytesToBigNum(dgst, mhash)!= E_OK) 
    {
        return E_NOT_OK;
    }
    if (Cry_SM2_BytesToBigNum(key, PrivateKey)!= E_OK) 
    {
        return E_NOT_OK;
    }
    // Convert private key to Montgomery format
    if (Cry_SM2_BigNumToMontgomery(d, key, GM_BN_N)!= E_OK) 
    {
        return E_NOT_OK;
    }

    // e = H(M)
    Cry_SM2_BigNumCopy(e, dgst);

    retry:

        if(USER_TESTCASE != 5U)
        {
            // Step 5: Generate random number k
            do {
                do {
                    // Generate random number into buffer
                    if (Cry_SM2_GenRandom(buf, 256)!= E_OK)
                    {
                        return E_NOT_OK; // Handle random generation error
                    }
                    // Convert random buffer to a big number
                    if (Cry_SM2_BytesToBigNum(k, buf)!= E_OK) 
                    {
                        return E_NOT_OK; // Handle conversion error
                    }
                } while (Cry_SM2_BigNumCmp(k, GM_BN_N) >= 0); // Ensure k < GM_BN_N, k >= GM_BN_N, generate a new random k
            } while (Cry_SM2_BigNumIsZero(k)); // Ensure k is not zero��k is zero, re-generate random k
        }
        else
        {
            // SM2 TEST CASE
            if (Cry_SM2_BytesToBigNum(k, TestK)!= E_OK) 
            {
                return E_NOT_OK;
            }
        }

     // Step 6: Compute (x, y) = kG
    if (Cry_SM2_PointMult(P, k, GM_MONT_G)!= E_OK) 
    {
        return E_NOT_OK;
    }
    // Extract x and y
    Cry_SM2_PointGetXY(P, x, y);

    // Step 7: Compute r = (e + x) mod n
    if (Cry_SM2_BigNumAdd(r, e, x, GM_BN_N)!= E_OK) 
    {
        return E_NOT_OK;
    }
    /* if r == 0 or r + k == n re-generate k */
    if (Cry_SM2_BigNumIsZero(r)) 
    {
        goto retry;
    }

    // Check r + k != n
    if (Cry_SM2_BigNumAdd(x, r, k, GM_BN_N)!= E_OK) 
    {
        return E_NOT_OK;
    }
    if (Cry_SM2_BigNumIsZero(x)) 
    {
        goto retry;
    }

    // Convert r to bytes
    Cry_SM2BnToBytes(r, SignatureR);

    // Step 8: Compute s = ((1 + d)^-1 * (k - r * d)) mod n
    if (Cry_SM2_BigNumToMontgomery(r, r, GM_BN_N)!= E_OK) 
    {
        return E_NOT_OK;
    }
    if (Cry_SM2_BigNumToMontgomery(k, k, GM_BN_N)!= E_OK) 
    {
        return E_NOT_OK;
    }
    if (Cry_SM2_MontgomeryModMult(e, r, d, GM_BN_N)!= E_OK) 
    {
        return E_NOT_OK;
    }

    Cry_SM2_BigNumSub(k, k, e, GM_BN_N);

    if (Cry_SM2_BigNumAdd(x, GM_BN_MONT_NONE, d, GM_BN_N)!= E_OK) 
    {
        return E_NOT_OK;
    }

    Cry_SM2_MontgomeryModInv(x, x, GM_BN_N);

    if (Cry_SM2_MontgomeryModMult(s, x, k, GM_BN_N)!= E_OK) 
    {
        return E_NOT_OK;
    }
    if(Cry_SM2_BigNumIsZero(s)) 
    {
        goto retry;
    }

    // Convert s to standard format
    Cry_SM2_MontgomeryToBigNum(s, s, GM_BN_N);
    Cry_SM2BnToBytes(s, SignatureS);

 return Result;
}

Std_ReturnType Cry_SM2_VerifyMsg(uint8 *PublicKey,const uint8 *Message, uint32 MessageLen, const uint8 *User_Id, uint32 User_Len, uint8 *SignatureR, uint8 *SignatureS)
{
    Std_ReturnType Result = E_OK;
    uint8 zhash[ECC_NUMWORD] = {0};
    uint8 mhash[ECC_NUMWORD] = {0};
    uint8 mMessage[ECC_NUMBITS * 8] = {0};
    sm3_ctx mza[1];

    sm2_point_t _zPubkey,*zPubkey=&_zPubkey;
    sm2_point_t _P, *P = &_P;
    sm2_point_t _Q, *Q = &_Q;
    sm2_bn_t t;
    sm2_bn_t dgst;


    /* Generate pre-compiled data Za */
    Cry_SM2_GenZA(PublicKey,User_Id,User_Len,zhash);
    /* Generate pre-compiled data mMessage */
    memcpy(mMessage,zhash,ECC_NUMWORD);
    memcpy(&mMessage[ECC_NUMWORD],Message,MessageLen);

    /* Generate the Hash Value of pre-compiled data mMessage */
    Cry_SM3_MainFunction(mMessage, (MessageLen + ECC_NUMWORD), mhash);

    Cry_SM2_BytesToBigNum(dgst, mhash);

    /* get the big num of Prikey */
    Cry_SM2PointFromBytes(zPubkey, PublicKey);

    // parse signature values
    Cry_SM2_BytesToBigNum(r, SignatureR);
    Cry_SM2_BytesToBigNum(s, SignatureS);
    if (Cry_SM2_BigNumIsZero(r)
    || Cry_SM2_BigNumCmp(r, GM_BN_N) >= 0
    || Cry_SM2_BigNumIsZero(s)
    || Cry_SM2_BigNumCmp(s, GM_BN_N) >= 0) {
    return E_NOT_OK;
    }

    // parse public key
    Cry_SM2_PointCopy(P, zPubkey);

    // t = r + s (mod n)
    // check t != 0
    Cry_SM2_BigNumAdd(t, r, s, GM_BN_N);
    if (Cry_SM2_BigNumIsZero(t)) {
    return E_NOT_OK;
    }

    // Q = s * G + t * P
    Cry_SM2_PointMult(Q, s, GM_MONT_G);
    Cry_SM2_PointMult(P, t, P);
    Cry_SM2_PointAdd(Q, Q, P);
    Cry_SM2_PointGetXY(Q, x, NULL);

    // e = H(M)
    // r' = e + x (mod n)
    Cry_SM2_BigNumCopy(e, dgst);
    Cry_SM2_BigNumAdd(e, e, x, GM_BN_N);

    // check if r == r'
    if (Cry_SM2_BigNumCmp(e, r) == 0) {
        Result = E_OK;
    } else {
        Result = E_NOT_OK;
    }
    
    return Result;
}

static Std_ReturnType Cry_SM2CheckPublicKey(const sm2_point_t * pub_key) {
    if(Cry_SM2IsAtInfinity(pub_key)) {
        return E_NOT_OK;
    }
    sm2_bn_t x, y, r;
    Cry_SM2_PointGetXY(pub_key, x, y);
    if(Cry_SM2_BigNumIsZero(x) || Cry_SM2_BigNumCmp(x, GM_BN_P) >= 0) {
        return E_NOT_OK;
    }
    if(Cry_SM2_BigNumIsZero(y) || Cry_SM2_BigNumCmp(y, GM_BN_P) >= 0) {
        return E_NOT_OK;
    }
    Cry_SM2_BigNumToMontgomery(x, x, GM_BN_P);
    Cry_SM2_BigNumToMontgomery(y, y, GM_BN_P);
    Cry_SM2_MontgomeryModSqr(r, x, GM_BN_P);
    Cry_SM2_BigNumAdd(r, r, GM_BN_MONT_A, GM_BN_P);
    Cry_SM2_MontgomeryModMult(r, r, x, GM_BN_P);
    Cry_SM2_BigNumAdd(r, r, GM_BN_MONT_B, GM_BN_P);
    Cry_SM2_MontgomeryModSqr(y, y, GM_BN_P);
    if(Cry_SM2_BigNumCmp(r, y) != 0) {
        return E_NOT_OK;
    }
    return E_OK;
}
static Std_ReturnType Cry_SM2RecoverPublicKey(sm2_ctx * ctx, const uint8 * key, uint32 kLen) 
{

    Cry_SM2PointDecode(&ctx->public_key, key);
    if(Cry_SM2CheckPublicKey(&ctx->public_key) != E_OK) {
        return E_NOT_OK;
    }
    return E_OK;
}

static int Cry_SM2RecoverPrivateKey(sm2_ctx * ctx, const uint8 * key, uint32 kLen) 
{
    if(kLen != 32) {
        return E_NOT_OK;
    }
    Cry_SM2_BytesToBigNum(ctx->private_key, key);
    // check k ? [1, n-2]
    if(Cry_SM2_BigNumIsZero(ctx->private_key) || Cry_SM2_BigNumCmp(ctx->private_key, SM2_BN_N_SUB_ONE) >= 0) {
        return E_NOT_OK;
    }
    // check public key
    Cry_SM2_PointMult(&ctx->public_key, ctx->private_key, GM_MONT_G);
    if(Cry_SM2CheckPublicKey(&ctx->public_key) != E_OK) {
        return E_NOT_OK;
    }
    return E_OK;
}
/* SM2 Encrypt */

/* SM2 Encrypt Init */
static Std_ReturnType Cry_SM2EncryptInitInternal(sm2_ctx * ctx, const uint8 * key, uint32 kLen, uint8 c1[64], const sm2_bn_t test_key) 
{
    sm2_point_t p;
    if(Cry_SM2RecoverPublicKey(ctx, key, kLen) == E_NOT_OK) {
        return E_NOT_OK;
    }
    Cry_SM2_PointMult(&p, test_key, GM_MONT_G);
    Cry_SM2PointToBytes(&p, c1);

    Cry_SM2_PointMult(&p, test_key, &ctx->public_key);
    Cry_SM2PointToBytes(&p, ctx->x2y2);
    ctx->cur_buf_len = 0;
    ctx->ct = 1;
    Cry_SM3_Init(&ctx->sm3_ctxset);
    Cry_SM3_Update(&ctx->sm3_ctxset, ctx->x2y2, 32);
    return E_OK;
}

/**
 * Initialization of encryption 
 * @param ctx SM2 context
 * @param key The public key PC || x || y
 * @param kLen The public key must be 32 or 64 bytes long and the private key 32 bytes long
 * @return E_OK returns success, otherwise the key is invalid
 */
Std_ReturnType Cry_SM2EncryptInit(sm2_ctx * ctx, const uint8 * key, uint32 kLen, uint8 c1[64]) 
{
    Std_ReturnType Result = E_OK;
    sm2_bn_t k;
    uint8 buf[256] = {0};
    do {
        do {
            Cry_SM2_GenRandom(buf, 256);
            Cry_SM2_BytesToBigNum(k, buf);
        } while (Cry_SM2_BigNumCmp(k, GM_BN_N) >= 0);
    } while (Cry_SM2_BigNumIsZero(k));
    Result = Cry_SM2EncryptInitInternal(ctx, key, kLen, c1, k);
    return Result;
}
/* SM2 Encrypt Update */
/**
 * Encryption one round
 * @param ctx SM2 context
 * @param output Output buffer
 * @param len Length of data to be processed in this round
 */
static void Cry_SM2EncryptUpdateOneRound(sm2_ctx * ctx, uint8 * output, uint32 len) 
{
    uint32 i;
    sm3_ctx sm3_ctx;
    Cry_SM3_Init(&sm3_ctx);
    Cry_SM3_Update(&sm3_ctx, ctx->x2y2, 64);
    SM2_PUT_UINT32_BE(ctx->ct, output, 0);
    Cry_SM3_Update(&sm3_ctx, output, 4);
    Cry_SM3_GetHash(&sm3_ctx, output);
    for(i = 0; i < len; i++) {
        output[i] ^= ctx->buf[i];
    }
    Cry_SM3_Update(&ctx->sm3_ctxset, ctx->buf, len);
    ctx->cur_buf_len = 0;
    ctx->ct++;
}
/**
 * Encryption Add data
 * @param ctx SM2 context
 * @param input Pending data
 * @param iLen Length of data to be processed
 * @param output The output buffer must be a multiple of 32 bytes, larger than iLen
 * @return Returns the length of the processed data
 */
Std_ReturnType Cry_SM2EncryptUpdate(sm2_ctx * ctx, const uint8 * input, uint32 iLen, uint8 * output) 
{
    uint32 rLen = 0;
    while(iLen--) {
        ctx->buf[ctx->cur_buf_len++] = *input++;

        // ?????
        if(ctx->cur_buf_len == 32) {
            Cry_SM2EncryptUpdateOneRound(ctx, output + rLen, 32);
            rLen += 32;
        }
    }
    return rLen;
}
/* SM2 Encrypt Finish */
/**
 * End encryption
 * @param ctx SM2 context
 * @param output The output buffer must be a multiple of 32 bytes, at least 32 bytes
 * @param c3 encryption output C3
 * @return Returns the length of the processed data
 */
Std_ReturnType Cry_SM2EncryptFinish(sm2_ctx * ctx, uint8 * output, uint8 c3[32]) 
{
    uint32 rLen = ctx->cur_buf_len;
    Cry_SM2EncryptUpdateOneRound(ctx, output, rLen);
    Cry_SM3_Update(&ctx->sm3_ctxset, ctx->x2y2 + 32, 32);
    Cry_SM3_GetHash(&ctx->sm3_ctxset, c3);
    return rLen;
}

/* SM2 Encrypt MainFunction */
Std_ReturnType Cry_SM2Encrypt(uint8 *PublicKey, uint8 *message, uint32 messageLen, uint8 *output)
{
    Std_ReturnType Result = E_OK; 
    sm2_ctx ctx[1];
    uint32 rLen;
    uint32 remainlen;
    uint8 c3checkbuf[32] = {0u};
    uint8 c3buf[32] = {0u};
    uint8 remaindata[32]= {0u};
    
    Cry_SM2EncryptInit(ctx, PublicKey, SM2_CRYPTPUBKEY_DEFAULTLEN, output);
    rLen = Cry_SM2EncryptUpdate(ctx, message, messageLen, &output[SM2_C1_DEFAULTLEN + SM2_C3_DEFAULTLEN]);
    remainlen = ctx->cur_buf_len;
    Cry_SM2EncryptFinish(ctx, remaindata, c3buf);

    memcpy(&output[SM2_C1_DEFAULTLEN + SM2_C3_DEFAULTLEN + rLen],remaindata,remainlen);
    memcpy(&output[SM2_C1_DEFAULTLEN],c3buf,SM2_C3_DEFAULTLEN);

    if(memcmp(c3buf, c3checkbuf, SM2_C3_DEFAULTLEN) == E_OK) 
    {
        Result = E_NOT_OK; 
    }
    else
    {
        Result = E_OK;
    }
    
    return Result;
}

/* SM2 Decrypt Init */
/**
 * Initialization of decryption 
 * @param ctx SM2 context
 * @param key The private key is used for decryption.
 * @param kLen The private key 32 bytes long
 * @return E_OK returns success, otherwise the key is invalid
 */
Std_ReturnType Cry_SM2DecryptInit(sm2_ctx * ctx, const uint8 * key, uint32 kLen, uint8 c1[64]) 
{
    sm2_point_t p;
    if(Cry_SM2RecoverPrivateKey(ctx, key, kLen) == E_NOT_OK) {
        return E_NOT_OK;
    }

    Cry_SM2PointFromBytes(&p, c1);
    Cry_SM2_PointMult(&p, ctx->private_key, &p);
    Cry_SM2PointToBytes(&p, ctx->x2y2);
    
    ctx->cur_buf_len = 0;
    ctx->ct = 1;
    Cry_SM3_Init(&ctx->sm3_ctxset);
    Cry_SM3_Update(&ctx->sm3_ctxset, ctx->x2y2, 32);
    return E_OK;
}

/* SM2 Decrypt Update */
/**
 * Decryption one round
 * @param ctx SM2 context
 * @param output Output buffer
 * @param len Length of data to be processed in this round
 */
static void Cry_SM2DecryptUpdateOneRound(sm2_ctx * ctx, uint8 * output, uint32 len) 
{
    uint32 i;
    sm3_ctx sm3_ctx;
    Cry_SM3_Init(&sm3_ctx);
    Cry_SM3_Update(&sm3_ctx, ctx->x2y2, 64);
    SM2_PUT_UINT32_BE(ctx->ct, output, 0);
    Cry_SM3_Update(&sm3_ctx, output, 4);
    Cry_SM3_GetHash(&sm3_ctx, output);
    for(i = 0; i < len; i++) {
        output[i] ^= ctx->buf[i];
    }
    Cry_SM3_Update(&ctx->sm3_ctxset, output, len);
    ctx->cur_buf_len = 0;
    ctx->ct++;
}
/**
 * Decryption Add data
 * @param ctx SM2 context
 * @param input Pending data
 * @param iLen Length of data to be processed
 * @param output The output buffer must be a multiple of 32 bytes, larger than iLen
 * @return Returns the length of the processed data
 */
Std_ReturnType Cry_SM2DecryptUpdate(sm2_ctx * ctx, const uint8 * input, uint32 iLen, uint8 * output) 
{
    uint32 rLen = 0;
    while(iLen--) {
        ctx->buf[ctx->cur_buf_len++] = *input++;

        // ?????
        if(ctx->cur_buf_len == 32) {
            Cry_SM2DecryptUpdateOneRound(ctx, output + rLen, 32);
            rLen += 32;
        }
    }
    return rLen;
}

/* SM2 Decrypt Finish */
/**
 * End encryption
 * @param ctx SM2 context
 * @param output The output buffer must be a multiple of 32 bytes, at least 32 bytes
 * @param c3 encryption output C3
 * @return Returns the length of the processed data
 */
Std_ReturnType Cry_SM2DecryptFinish(sm2_ctx * ctx, uint8 * output, uint8 c3[32]) 
{
    uint32 rLen = ctx->cur_buf_len;
    Cry_SM2DecryptUpdateOneRound(ctx, output, rLen);
    Cry_SM3_Update(&ctx->sm3_ctxset, ctx->x2y2 + 32, 32);
    Cry_SM3_GetHash(&ctx->sm3_ctxset, c3);
    return rLen;
}

/* SM2 Decrypt MainFunction */
Std_ReturnType Cry_SM2Decrypt(uint8 *PrivateKey, uint8 *ciphermessage, uint32 ciphermessageLen, uint8 *output)
{
    Std_ReturnType Result = E_OK; 
    sm2_ctx ctx[1];
    uint32 rLen;
    uint32 remainlen;
    uint8 c3buf[32];
    uint8 remaindata[32];
    
    Cry_SM2DecryptInit(ctx, PrivateKey, SM2_CRYPTPRIKEY_DEFAULTLEN, ciphermessage);
    rLen = Cry_SM2DecryptUpdate(ctx, &ciphermessage[SM2_C1_DEFAULTLEN + SM2_C3_DEFAULTLEN], ciphermessageLen, output);
    remainlen = ctx->cur_buf_len;
    Cry_SM2DecryptFinish(ctx, remaindata, c3buf);

    memcpy(&output[rLen],remaindata,remainlen);

    if(memcmp(c3buf, &ciphermessage[SM2_C1_DEFAULTLEN], SM2_C3_DEFAULTLEN) != E_OK) 
    {
        Result = E_NOT_OK; 
        memset(output,0u,ciphermessageLen);
    }
    else
    {
        Result = E_OK;
    }
    
    return Result;
}